using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Coriander.Xmpp.Xmpp.Security
{
    /// <summary>
    /// 
    /// </summary>
    /// <remarks>
    /// JId (Jabber identifier) consists of several parts;
    /// 
    ///     jid             = [ node "@" ] domain [ "/" resource ]
    ///     domain          = fqdn / address-literal
    ///     fqdn            = (sub-domain 1*("." sub-domain))
    ///     sub-domain      = (internationalized domain label)
    ///     address-literal = IPv4address / IPv6address
    /// 
    /// Seealso: http://www.ietf.org/rfc/rfc3920.txt, 3. Addressing scheme
    /// </remarks>
    public struct Jid
    {
        static Regex r = new Regex(
            "(?<node>[^@]+)@(?<domain>[^/]+)([/]{1}(?<resource>[\\s\\S]+))?",
            RegexOptions.Compiled
        );

        /// <summary>
        /// 
        /// </summary>
        public static readonly Jid Empty = new Jid(null, null, null);

        readonly String value, node, domain, resource, user;

        /// <summary>
        /// 
        /// </summary>
        public String Domain
        {
            get { return domain; }
        } 

        /// <summary>
        /// 
        /// </summary>
        public String Node
        {
            get { return node; }
        }

        /// <summary>
        /// 
        /// </summary>
        public String Resource
        {
            get { return resource; }
        }

        /// <summary>
        /// 
        /// </summary>
        public String User
        {
            get { return user; }
        } 

        /// <summary>
        /// 
        /// </summary>
        public String Value
        {
            get { return this.value; }
        }

        /// <summary>
        /// ctor : String, String, String
        /// </summary>
        /// <param name="node"></param>
        /// <param name="domain"></param>
        /// <param name="resource"></param>
        public Jid(String node, String domain, String resource) 
        {
            this.node       = node;
            this.domain     = domain;
            this.resource   = resource;

            this.user       = FormatUser(node, domain); 
            this.value      = FormatValue(node, domain, resource);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static implicit operator String(Jid instance)
        {
            return instance.ToString(); 
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Value; 
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        static String Clean(String value) 
        {
            if (null == value)
                return null;

            if ((value = value.Trim()).Length == 0)
                return null;

            return value;
        }

        /// <summary>
        ///  Checks if the supplied String is either null, or contains only whitespace.
        /// </summary>
        /// <param name="value"></param>
        static Boolean IsNullOrEmpty(String value) 
        {
            String temp = Clean(value);

            return null == temp || String.IsNullOrEmpty(temp); 
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="node"></param>
        /// <param name="domain"></param>
        /// <returns></returns>
        static String FormatUser(String node, String domain) 
        {
            return String.Format("{0}@{1}", node, domain); 
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="domain"></param>
        /// <param name="resource"></param>
        /// <returns></returns>
        static String FormatValue(String node, String domain, String resource) 
        {
            return String.Format(
                "{0}{1}{2}",
                IsNullOrEmpty(node) ? String.Empty : node + "@",
                domain,
                IsNullOrEmpty(resource) ? String.Empty : "/" + resource
            ); 
        }

        /// <summary>
        /// Parses the supplied String into a Jid
        /// </summary>
        /// <param name="value"></param>
        public static Jid Parse(String value) 
        {
            if (null == value)
                throw new ArgumentNullException("value");

            Match m = null;

            if ((m = r.Match(value)).Success)
            {
                return new Jid(
                    m.Groups["node"].Value,
                    m.Groups["domain"].Value,
                    m.Groups["resource"].Value
                ); 
            }

            throw new FormatException(
                String.Format(
                    "Unable to parse supplied value to Jid. \"{0}\"", value
                )
            );
        }
    }
}
